]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
init: Move Meta main loop into JavaScript after GJS context is initialized
authorEvan Welsh <contact@evanwelsh.com>
Wed, 7 Jun 2023 15:58:08 +0000 (08:58 -0700)
committerFlorian Müllner <fmuellner@gnome.org>
Wed, 7 Jun 2023 19:23:27 +0000 (19:23 +0000)
gjs now has an internal mainloop that it can spin to resolve
module imports. That loop uses the thread default context,
so its possible that other sources, namely from mutter, get
dispatched when iterating the context. If that happens before
mutter is properly initialized, this will lead to a crash.

GjsContext needs to iterate its internal mainloop when initializing
to resolve internal modules, to avoid iterating Meta's mainloop and
triggering events before Meta is ready we will initialize the Shell
global and thus the GjsContext (js_context) before Meta.

Once GjsContext is initialized, we can call meta_context_setup().
Once Meta is setup and started, we'll run init.js which uses GJS'
internal promises API to set a "mainloop hook". The mainloop hook
is run immediately after the module returns so GJS will not attempt
to iterate the main loop again before exiting.

Also adjust the 'headlessStart' test to not wait for the
MetaContext::started signal, as that signal has now already
been emitted when the code is executed.

https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/6691

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2781>

js/perf/headlessStart.js
js/ui/init.js
src/gnome-shell-plugin.c
src/main.c

index ace6453558a6b918cfe0dec5f5f357d0383f3546..0f18447e3e6cf9b6688a92fc7411a81698e585cf 100644 (file)
@@ -23,15 +23,12 @@ function init() {
     global.connect('shutdown', () => {
         _testMonitor?.destroy();
     });
-    global.context.connect('started',
+    GLib.timeout_add_seconds(
+        GLib.PRIORITY_LOW, 2,
         () => {
-            GLib.timeout_add_seconds(
-                GLib.PRIORITY_LOW, 2,
-                () => {
-                    log('Connecting 1280x720 test monitor');
-                    _testMonitor = MetaTest.TestMonitor.new(
-                        global.context, 1280, 720, 60.0);
-                });
+            log('Connecting 1280x720 test monitor');
+            _testMonitor = MetaTest.TestMonitor.new(
+                global.context, 1280, 720, 60.0);
         });
     Scripting.defineScriptEvent('monitorsChanged', 'Monitors changed');
 
index a0fe63343fa787e45ba3c3acc08f9a11b5d2fdb5..32d3c68ba57dae91d4ea7993b1505239d833ee73 100644 (file)
@@ -1,6 +1,25 @@
-import { setConsoleLogDomain } from 'console';
+import {setConsoleLogDomain} from 'console';
+import GLib from 'gi://GLib';
+import {exit} from 'system';
 
 setConsoleLogDomain('GNOME Shell');
 
 imports.ui.environment.init();
-imports.ui.main.start();
+
+// Run the Mutter main loop after
+// GJS finishes resolving this module.
+imports._promiseNative.setMainLoopHook(() => {
+    // Queue starting the shell
+    GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
+        try {
+            imports.ui.main.start();
+        } catch (e) {
+            logError(e);
+            exit(1);
+        }
+        return GLib.SOURCE_REMOVE;
+    });
+
+    // Run the meta context's main loop
+    global.context.run_main_loop();
+});
index 5364f043a021d780e26417bd9f1effcfb52bbeaf..39db3aefde62b49891f68772b7809d7d8760349d 100644 (file)
@@ -105,9 +105,6 @@ static void
 gnome_shell_plugin_start (MetaPlugin *plugin)
 {
   GnomeShellPlugin *shell_plugin = GNOME_SHELL_PLUGIN (plugin);
-  GError *error = NULL;
-  uint8_t status;
-  GjsContext *gjs_context;
   ClutterBackend *backend;
 
   backend = clutter_get_default_backend ();
@@ -123,30 +120,6 @@ gnome_shell_plugin_start (MetaPlugin *plugin)
 
   shell_plugin->global = shell_global_get ();
   _shell_global_set_plugin (shell_plugin->global, META_PLUGIN (shell_plugin));
-
-  gjs_context = _shell_global_get_gjs_context (shell_plugin->global);
-
-  if (!gjs_context_eval_module_file (gjs_context,
-                                     "resource:///org/gnome/shell/ui/init.js",
-                                     &status,
-                                     &error))
-    {
-      g_message ("Execution of main.js threw exception: %s", error->message);
-      g_error_free (error);
-      /* We just exit() here, since in a development environment you'll get the
-       * error in your shell output, and it's way better than a busted WM,
-       * which typically manifests as a white screen.
-       *
-       * In production, we shouldn't crash =)  But if we do, we should get
-       * restarted by the session infrastructure, which is likely going
-       * to be better than some undefined state.
-       *
-       * If there was a generic "hook into bug-buddy for non-C crashes"
-       * infrastructure, here would be the place to put it.
-       */
-      g_object_unref (gjs_context);
-      exit (1);
-    }
 }
 
 static ShellWM *
index e81f92c44db950d303a91cbe1ca5da284bde1487..1bfa05e4bd6efe109e59a7570a74a1110ec91cb3 100644 (file)
@@ -608,11 +608,8 @@ main (int argc, char **argv)
   init_signal_handlers (context);
   change_to_home_directory ();
 
-  if (!meta_context_setup (context, &error))
-    {
-      g_printerr ("Failed to setup: %s\n", error->message);
-      return EXIT_FAILURE;
-    }
+  if (session_mode == NULL)
+    session_mode = is_gdm_mode ? (char *)"gdm" : (char *)"user";
 
   /* FIXME: Add gjs API to set this stuff and don't depend on the
    * environment.  These propagate to child processes.
@@ -620,24 +617,6 @@ main (int argc, char **argv)
   g_setenv ("GJS_DEBUG_OUTPUT", "stderr", TRUE);
   g_setenv ("GJS_DEBUG_TOPICS", "JS ERROR;JS LOG", TRUE);
 
-  shell_init_debug (g_getenv ("SHELL_DEBUG"));
-
-  shell_dbus_init (meta_context_is_replacing (context));
-  shell_a11y_init ();
-  shell_perf_log_init ();
-  shell_introspection_init ();
-  shell_fonts_init ();
-
-  g_log_set_writer_func (default_log_writer, NULL, NULL);
-
-  /* Initialize the global object */
-  if (session_mode == NULL)
-    session_mode = is_gdm_mode ? (char *)"gdm" : (char *)"user";
-
-  _shell_global_init ("session-mode", session_mode,
-                      "force-animations", force_animations,
-                      NULL);
-
   dump_gjs_stack_on_signal (SIGABRT);
   dump_gjs_stack_on_signal (SIGFPE);
   dump_gjs_stack_on_signal (SIGIOT);
@@ -649,6 +628,33 @@ main (int argc, char **argv)
       dump_gjs_stack_on_signal (SIGSEGV);
     }
 
+  /* Initialize the Shell global, including GjsContext
+   * GjsContext will iterate the default main loop to
+   * resolve internal modules.
+   */
+  _shell_global_init ("session-mode", session_mode,
+                      "force-animations", force_animations,
+                      NULL);
+
+  /* Setup Meta _after_ the Shell global to avoid GjsContext
+   * iterating on the main loop once Meta starts adding events
+   */
+  if (!meta_context_setup (context, &error))
+    {
+      g_printerr ("Failed to setup: %s\n", error->message);
+      return EXIT_FAILURE;
+    }
+
+  shell_init_debug (g_getenv ("SHELL_DEBUG"));
+
+  shell_dbus_init (meta_context_is_replacing (context));
+  shell_a11y_init ();
+  shell_perf_log_init ();
+  shell_introspection_init ();
+  shell_fonts_init ();
+
+  g_log_set_writer_func (default_log_writer, NULL, NULL);
+
   shell_profiler_init ();
 
   if (meta_context_get_compositor_type (context) == META_COMPOSITOR_TYPE_WAYLAND)
@@ -660,10 +666,31 @@ main (int argc, char **argv)
       return EXIT_FAILURE;
     }
 
-  if (!meta_context_run_main_loop (context, &error))
+  /* init.js calls meta_context_start_main_loop(), gjs_context_eval_module_file()
+   * will not return until Mutter is exited.
+   */
+  GjsContext *gjs_context = _shell_global_get_gjs_context (shell_global_get());
+  uint8_t status;
+  if (!gjs_context_eval_module_file (gjs_context,
+                                     "resource:///org/gnome/shell/ui/init.js",
+                                     &status,
+                                     &error))
     {
-      g_printerr ("GNOME Shell terminated with an error: %s\n", error->message);
-      ecode = EXIT_FAILURE;
+      g_message ("Execution of main.js threw exception: %s", error->message);
+      g_error_free (error);
+      /* We just exit() here, since in a development environment you'll get the
+       * error in your shell output, and it's way better than a busted WM,
+       * which typically manifests as a white screen.
+       *
+       * In production, we shouldn't crash =)  But if we do, we should get
+       * restarted by the session infrastructure, which is likely going
+       * to be better than some undefined state.
+       *
+       * If there was a generic "hook into bug-buddy for non-C crashes"
+       * infrastructure, here would be the place to put it.
+       */
+      g_object_unref (gjs_context);
+      exit (1);
     }
 
   g_message ("Shutting down GNOME Shell");